package com.hanshg.cherry.controller.oauth;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.hanshg.cherry.base.core.Constants;
import com.hanshg.cherry.dto.LoginUser;
import com.hanshg.cherry.dto.oauth.AccessTokenWX;
import com.hanshg.cherry.dto.oauth.WechatUserUnionID;
import com.hanshg.cherry.mapper.PermissionMapper;
import com.hanshg.cherry.model.SysPermission;
import com.hanshg.cherry.model.SysUser;
import com.hanshg.cherry.service.oauth.OAuthService;
import com.hanshg.cherry.service.oauth.TencentLoginService;
import com.hanshg.cherry.util.core.DateUtils;
import com.hanshg.cherry.util.oauth.AesUtil;
import com.qq.connect.QQConnectException;
import com.qq.connect.api.OpenID;
import com.qq.connect.api.qzone.UserInfo;
import com.qq.connect.javabeans.AccessToken;
import com.qq.connect.javabeans.qzone.UserInfoBean;
import com.qq.connect.oauth.Oauth;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.List;

/**
 * 腾讯第三方登录
 */
@Api(tags = "腾讯登录控制层")
@Slf4j
@Controller
public class TencentLoginController {

    @Autowired
    private TencentLoginService tencentLoginService;

    @Autowired
    private OAuthService OAuthService;

    @Autowired
    private PermissionMapper permissionMapper;

    @GetMapping("/wxLogin")
    @ApiOperation(value = "微信登录认证地址", notes = "微信登录认证地址")
    @ApiOperationSupport(author = "柠檬水 cherryok@126.com")
    public String wxLogin() {
        log.info("微信登录");
        String url = tencentLoginService.wxLoginUrl();
        return "redirect:" + url;
    }

    @RequestMapping("/qqLogin")
    @ApiOperation(value = "QQ登录认证地址", notes = "QQ登录认证地址")
    @ApiOperationSupport(author = "柠檬水 cherryok@126.com")
    public void qqLogin(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/html;charset=utf-8");
        try {
            log.info("QQ登录");
            response.sendRedirect(new Oauth().getAuthorizeURL(request));
        } catch (QQConnectException e) {
            e.printStackTrace();
        }
    }

    /**
     * 回调地址处理
     *
     * @param code
     * @param state
     * @return
     */
    //@GetMapping(value = "/callbackwechat_open")
    @ApiOperation(value = "微信登录回调函数", notes = "微信登录回调函数")
    @ApiOperationSupport(author = "柠檬水 cherryok@126.com")
    public ModelAndView wxcallback(HttpServletRequest request, String code, String state) {
        String access_token;
        String openid;
        if (code != null && state != null) {
            // 验证state为了用于防止跨站请求伪造攻击
            String decrypt = AesUtil.decrypt(AesUtil.parseHexStr2Byte(state), AesUtil.PASSWORD_SECRET_KEY, 16);
            if (!decrypt.equals(Constants.PWD_MD5 + DateUtils.dateTime())) {
                ModelAndView model = new ModelAndView("forward:/login.html");
                return model;
            }
            AccessTokenWX access = tencentLoginService.getAccessToken(code);
            if (access != null) {
                // 把获取到的access_token和openId赋值给变量
                access_token = access.getAccess_token();
                openid = access.getOpenid();

                // 存在则把当前账号信息授权给扫码用户
                // 拿到openid获取微信用户的基本信息
                WechatUserUnionID userUnionID = tencentLoginService.getUserUnionID(access_token, openid);
                LoginUser loginUser = new LoginUser();
                SysUser sysUser = OAuthService.wxLogin(userUnionID, userUnionID.getOpenid());
                log.info("微信登录成功：" + sysUser);
                BeanUtils.copyProperties(sysUser, loginUser);

                //获取权限
                List<SysPermission> permissions = permissionMapper.listByUserId(loginUser.getId());
                loginUser.setPermissions(permissions);

                // 登录系统
                log.info("系统认证启动");
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginUser, loginUser.getPassword(), loginUser.getAuthorities());
                authentication.setDetails(loginUser);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                log.info("系统认证通过");

                HttpSession session = request.getSession();
                session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
                Authentication authenticated = SecurityContextHolder.getContext().getAuthentication();

                log.info("认证通过信息：" + authenticated);
                //存储信息返回页面
                ModelAndView model = new ModelAndView("forward:/");
                model.addObject("authentication", authenticated);
                return model;
            }
        }
        return null;
    }

    /**
     * 回调
     *
     * @param request
     * @param response
     * @throws Exception
     */
    //@RequestMapping("/callbackqq")
    @ApiOperation(value = "QQ登录回调函数", notes = "QQ登录回调函数")
    @ApiOperationSupport(author = "柠檬水 cherryok@126.com")
    public ModelAndView qqcallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setContentType("text/html;charset=UTF-8");
        try {
            AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);
            String accessToken, openID;

            if (accessTokenObj.getAccessToken().equals("")) {
//                我们的网站被CSRF攻击了或者用户取消了授权
                throw new UsernameNotFoundException("用户取消了授权或者没有获取到响应参数");
            } else {
                accessToken = accessTokenObj.getAccessToken();

                // 利用获取到的accessToken 去获取当前用的openid -------- start
                OpenID openIDObj = new OpenID(accessToken);

                openID = openIDObj.getUserOpenID();

                UserInfoBean userInfoBean = new UserInfo(accessToken, openID).getUserInfo();
                if (userInfoBean.getRet() == 0) {
                    LoginUser loginUser = new LoginUser();
                    SysUser sysUser = OAuthService.qqLogin(userInfoBean, openID);
                    log.info("QQ登录成功：" + sysUser);
                    BeanUtils.copyProperties(sysUser, loginUser);

                    //获取权限
                    List<SysPermission> permissions = permissionMapper.listByUserId(loginUser.getId());
                    loginUser.setPermissions(permissions);

                    // 登录系统
                    log.info("系统认证启动");
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginUser, loginUser.getPassword(), loginUser.getAuthorities());
                    authentication.setDetails(loginUser);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    log.info("系统认证通过");

                    HttpSession session = request.getSession();
                    session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());
                    Authentication authenticated = SecurityContextHolder.getContext().getAuthentication();

                    log.info("认证通过信息：" + authenticated);
                    //存储信息返回页面
                    ModelAndView model = new ModelAndView("forward:/");
                    model.addObject("authentication", authenticated);
                    return model;
                } else {
                    throw new UsernameNotFoundException("很抱歉，我们没能正确获取到您的信息，原因是： " + userInfoBean.getMsg());
                }
            }
        } catch (QQConnectException e) {
            throw new UsernameNotFoundException("很抱歉，QQ登录异常，原因是： " + e.getMessage());
        }
    }
}